#include "../pre_emptive_os/api/osapi.h"
#include "../pre_emptive_os/api/general.h"
#include <printf_P.h>
#include <ea_init.h>
#include <lpc2xxx.h>
#include <consol.h>
#include <printf_P.h>
#include "fan.h"
#include "joy.h"
#include "lcd.h"
#include "lm75.h"

#define LCD_BACKLIGHT 0x40000000  //P0.30
#define HYST			0.5
#define	POWER_CHANGE	10	 //w %
#define ENDL writeLCD(0, 0xA8); delay37us();

float desiredTemp = 23.0;
tU32 buttonsState, oldButtonsState, newButtonsState;
tU8 tempSensor = 0x92;

#define INIT_PROC_STACK_SIZE 2048
#define LEDS_PROC_STACK_SIZE 2048
#define DISPLAY_PROC_STACK_SIZE 2048
#define TEMPREAD_PROC_STACK_SIZE 2048
#define MOTOR_PROC_STACK_SIZE 2048

static tU8 initProcStack[INIT_PROC_STACK_SIZE];
static tU8 ledsProcStack[LEDS_PROC_STACK_SIZE];
static tU8 displayProcStack[DISPLAY_PROC_STACK_SIZE];
static tU8 tempReadProcStack[TEMPREAD_PROC_STACK_SIZE];
static tU8 motorProcStack[MOTOR_PROC_STACK_SIZE];

static tU8 initProcId;
static tU8 ledsProcId;
static tU8 displayProcId;
static tU8 tempReadProcId;
static tU8 motorProcPid;

volatile int TEMP;
volatile int MAX_TEMP;
volatile unsigned short LEDS_ON;

static void initProc(void* arg);
static void ledsProc(void* arg);
static void displayProc(void (*errorHandler)(int, char *, int));

tU16 tempRead(tU8 tempSensor);
volatile tU32 msClock;

static void motorProc(void* arg) {
	for (;;) {
		adjustMotorToTemp(TEMP);
		osSleep(10);
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Main. The first function to execute
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main(void) {
	tU8 error;
	TEMP = 30;
	MAX_TEMP = 20;
	osCreateProcess(initProc, initProcStack, INIT_PROC_STACK_SIZE, &initProcId, 3, NULL, &error);
	osStartProcess(initProcId, &error);
	osStart();
	return 0;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Checks if value of TEMP (which represents current
 * temperature  is read) is greater that MAX_TEMP (limit).
 * In case it is it makes led diodes blink
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void ledsProc(void * arg) {
	while(1) {
		if(TEMP > MAX_TEMP) { // blink
			printf("TEMPERATURE TOO HIGH:\t%d\n", TEMP);
			LEDS_ON = TRUE;
			turnOnLeds();
			osSleep(20);
			turnOffLeds();
			osSleep(20);
		}
		else if(LEDS_ON) {
			LEDS_ON = FALSE;
			turnOffLeds();
		}
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Handler for temperature taking too many digits
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void displayErrorHandler(int value, char * msg, int N) {
	resetCursor();
	if(msg == "MAX") ENDL;
	writeString("OVERFLOW        ", 16);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Displays current temperature and temperature limix (max)
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void displayProc(void (*errorHandler)(int, char *, int) ) {
	int max, present;
	while(1) {
		max = MAX_TEMP;
		present = TEMP;
		resetCursor();

		writeString("TMP: ", 5);
		int presentDigits = printInt(present);
		printCelsius();
		if(presentDigits > 9) {
			errorHandler(present, "TMP", 3);
		}
		printPadding(16-presentDigits);
		ENDL;

		writeString("MAX: ", 5);
		int maxDigits = printInt(max);
		printCelsius();
		if(maxDigits > 9) {
			errorHandler(max, "MAX", 3);
		}
		printPadding(16-maxDigits);

		while(1) { // waiting for change (active)
			if(max != MAX_TEMP || present != TEMP) {
				if(max < MAX_TEMP) {
					max++;
					MAX_TEMP = max;
				}
				else if(max > MAX_TEMP) {
					max--;
					MAX_TEMP = max;
				}
				printf("Temperature:\t%d\nMax:\t%d\n", TEMP, MAX_TEMP);
				break;
			}
		}
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Reads temperature from LM75
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void tempReadProc(void * arg) {
	while(1) {
		TEMP = readTemperature();
		osSleep(10);
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Procedure responsible for initializing the whole system
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void initProc(void* arg) {
	tU8 error;
	eaInit();
	ledsInit();
	lcdInit();
	initLM75();
	initJoy();
	initFan();

	printf("Initialization phase - Complete\n");

	osCreateProcess(ledsProc, ledsProcStack, LEDS_PROC_STACK_SIZE, &ledsProcId, 3, NULL, &error);
	osStartProcess(ledsProcId, &error);
	osCreateProcess(displayProc, displayProcStack, DISPLAY_PROC_STACK_SIZE, &displayProcId, 3, displayErrorHandler, &error);
	osStartProcess(displayProcId, &error);
	osCreateProcess(tempReadProc, tempReadProcStack, TEMPREAD_PROC_STACK_SIZE, &tempReadProcId, 3, NULL, &error);
	osStartProcess(tempReadProcId, &error);

	osCreateProcess(motorProc, motorProcStack, MOTOR_PROC_STACK_SIZE, &motorProcPid, 3, NULL, &error);
	osStartProcess(motorProcPid, &error);



	for (;;)
		osSleep(100);
}

/*****************************************************************************
 *
 * Description:
 *    The timer tick entry function that is called once every timer tick
 *    interrupt in the RTOS. Observe that any processing in this
 *    function must be kept as short as possible since this function
 *    execute in interrupt context.
 *
 * Params:
 *    [in] elapsedTime - The number of elapsed milliseconds since last call.
 *
 ****************************************************************************/
void appTick(tU32 elapsedTime) {
	msClock += elapsedTime;
}
